//-------------------------------------------------------------------
//	Copyright (c) 2012-2014 Zhirnov Andrey
//	This file is part of the "UXGEN-ES" project.
//	See copyright notice in "Engine.h".
//-------------------------------------------------------------------

#include "Graphics/GLshell/StateManager.h"
#include "Graphics/GLshell/PixelFormat.h"

namespace Engine
{
namespace Graphics
{

	namespace _pixel_format_helpers_
	{
		struct FormatInfo
		{
			typedef bool (* IsSupportedFunc_t)();

			EPixelFormat::type	format;
			gles::GLenum		internalFormat;
			gles::GLenum		pixelFormat;
			gles::GLenum		pixelType;
			uint				bitPerPixel;
			IsSupportedFunc_t	textureExt;
			IsSupportedFunc_t	framebufferExt;
		};

		static bool AlwaysTrue ()	{ return true; }
		static bool AlwaysFalse ()	{ return false; }

	}	// _pixel_format_helpers_


	
	// GetFormat
	bool EPixelFormat::GetFormat (gles::GLenum &ifmt, gles::GLenum &fmt, gles::GLenum &type, uint &bpp, const EPixelFormat::type format)
	{
		using namespace gles;
		using namespace _pixel_format_helpers_;

		enum {
			GL_RGB8		= OES_rgb8_rgba8::GL_RGB8,
			GL_RGBA8	= OES_rgb8_rgba8::GL_RGBA8,
			GL_R8		= EXT_texture_rg::GL_R8,
			GL_RG8		= EXT_texture_rg::GL_RG8,
			GL_RED		= EXT_texture_rg::GL_RED,
			GL_RG		= EXT_texture_rg::GL_RG,
			GL_ALPHA8	= EXT_texture_storage::GL_ALPHA8,
			GL_RGBA32F	= EXT_texture_storage::GL_RGBA32F,
			GL_RGB32F	= EXT_texture_storage::GL_RGB32F,
			GL_ALPHA32F	= EXT_texture_storage::GL_ALPHA32F,
			GL_RGBA16F	= EXT_texture_storage::GL_RGBA16F,
			GL_RGB16F	= EXT_texture_storage::GL_RGB16F,
			GL_ALPHA16F	= EXT_texture_storage::GL_ALPHA16F,
			GL_RGB10_A2	= EXT_texture_storage::GL_RGB10_A2,
			GL_RGB10	= EXT_texture_storage::GL_RGB10,
			GL_BGRA8	= EXT_texture_storage::GL_BGRA8,
			//GL_R8		= EXT_texture_storage::GL_R8,
			//GL_RG8		= EXT_texture_storage::GL_RG8,
			GL_R32F		= EXT_texture_storage::GL_R32F,
			GL_RG32F	= EXT_texture_storage::GL_RG32F,
			GL_R16F		= EXT_texture_storage::GL_R16F,
			GL_RG16F	= EXT_texture_storage::GL_RG16F,
			GL_HALF		= OES_texture_half_float::GL_HALF_FLOAT,
			GL_DEPTH16	= GL_DEPTH_COMPONENT16,
			GL_DEPTH	= GL_DEPTH_COMPONENT,
			GL_DEPTH24	= OES_depth24::GL_DEPTH_COMPONENT24,
			GL_DEPTH32	= OES_depth32::GL_DEPTH_COMPONENT32,
			GL_D24_S8	= OES_packed_depth_stencil::GL_DEPTH24_STENCIL8,
			GL_UINT24_8	= OES_packed_depth_stencil::GL_UNSIGNED_INT_24_8,
			GL_D_S		= OES_packed_depth_stencil::GL_DEPTH_STENCIL,
			GL_STENCIL1	= OES_stencil1::GL_STENCIL_INDEX1,
			GL_STENCIL4	= OES_stencil4::GL_STENCIL_INDEX4,
			GL_STENCIL	= 0,
			GL_STENCIL8	= GL_STENCIL_INDEX8,
			GL_RGB_ETC1	= OES_compressed_ETC1_RGB8_texture::GL_ETC1_RGB8,
		};
		

#		define EXT_TRUE				( & AlwaysTrue )
#		define EXT_FALSE			( & AlwaysFalse )
#		define EXT_RGB8_RGBA8		( & OES_rgb8_rgba8::IsSupported )
#		define EXT_TEXTURE_RG		( & EXT_texture_rg::IsSupported )
#		define EXT_TEXTURE_STORAGE	( & EXT_texture_storage::IsSupported )
#		define EXT_TEXTURE_HALF		( & OES_texture_half_float::IsSupported )
#		define EXT_TEXTURE_FLOAT	( & OES_texture_float::IsSupported )
#		define EXT_DEPTH24			( & OES_depth24::IsSupported )
#		define EXT_DEPTH32			( & OES_depth32::IsSupported )
#		define EXT_DEPTH_STENCIL	( & OES_packed_depth_stencil::IsSupported )
#		define EXT_STENCIL1			( & OES_stencil1::IsSupported )
#		define EXT_STENCIL4			( & OES_stencil4::IsSupported )
#		define EXT_COMPRESSED_ETC1	( & OES_compressed_ETC1_RGB8_texture::IsSupported )
		

		static const FormatInfo	formats[] = {
			// unsigned normalized
			{ EPixelFormat::ALPHA8,		GL_ALPHA8,		GL_ALPHA,	GL_UNSIGNED_BYTE,			8,		EXT_TRUE,	EXT_TRUE },
			{ EPixelFormat::R5_G6_B5,	GL_RGB565,		GL_RGB,		GL_UNSIGNED_SHORT_5_6_5,	16,		EXT_TRUE,	EXT_TRUE },
			{ EPixelFormat::RGB5_A1,	GL_RGB5_A1,		GL_RGBA,	GL_UNSIGNED_SHORT_5_5_5_1,	16,		EXT_TRUE,	EXT_TRUE },
			{ EPixelFormat::RGBA4,		GL_RGBA4,		GL_RGBA,	GL_UNSIGNED_SHORT_4_4_4_4,	16,		EXT_TRUE,	EXT_TRUE },
			{ EPixelFormat::RGBA8,		GL_RGBA8,		GL_RGBA,	GL_UNSIGNED_BYTE,			8*4,	EXT_TRUE,	EXT_TRUE },
			{ EPixelFormat::RGB8,		GL_RGB,			GL_RGB,		GL_UNSIGNED_BYTE,			8*3,	EXT_TRUE,	EXT_TRUE },
			// (OES_rgb8_rgba8)
			//{ EPixelFormat::RGB8,		GL_RGB8,		GL_RGB,		GL_UNSIGNED_BYTE,			8*3,	EXT_FALSE,	EXT_RGB8_RGBA8 },
			// (EXT_texture_rg)
			{ EPixelFormat::R8,			GL_R8,			GL_RED,		GL_UNSIGNED_BYTE,			8,		EXT_TEXTURE_STORAGE, EXT_TEXTURE_RG },
			{ EPixelFormat::RG8,		GL_RG8,			GL_RG,		GL_UNSIGNED_BYTE,			8*2,	EXT_TEXTURE_STORAGE, EXT_TEXTURE_RG },
			// float (EXT_texture_storage)
			{ EPixelFormat::RGBA32F,	GL_RGBA32F,		GL_RGBA,	GL_FLOAT,					32*4,	EXT_TEXTURE_STORAGE, EXT_TEXTURE_FLOAT	},
			{ EPixelFormat::RGBA16F,	GL_RGBA16F,		GL_RGBA,	GL_HALF,					16*4,	EXT_TEXTURE_STORAGE, EXT_TEXTURE_HALF	},
			{ EPixelFormat::RGB32F,		GL_RGB32F,		GL_RGB,		GL_FLOAT,					32*3,	EXT_TEXTURE_STORAGE, EXT_TEXTURE_FLOAT	},
			{ EPixelFormat::RGB16F,		GL_RGB16F,		GL_RGB,		GL_HALF,					16*3,	EXT_TEXTURE_STORAGE, EXT_TEXTURE_HALF	},
			{ EPixelFormat::RG32F,		GL_RG32F,		GL_RG,		GL_FLOAT,					32*2,	EXT_TEXTURE_STORAGE, EXT_TEXTURE_FLOAT	},
			{ EPixelFormat::RG16F,		GL_RG16F,		GL_RG,		GL_HALF,					16*2,	EXT_TEXTURE_STORAGE, EXT_TEXTURE_HALF	},
			{ EPixelFormat::R32F,		GL_R32F,		GL_RED,		GL_FLOAT,					32,		EXT_TEXTURE_STORAGE, EXT_TEXTURE_FLOAT	},
			{ EPixelFormat::R16F,		GL_R16F,		GL_RED,		GL_HALF,					16,		EXT_TEXTURE_STORAGE, EXT_TEXTURE_HALF	},
			{ EPixelFormat::ALPHA32F,	GL_ALPHA32F,	GL_ALPHA,	GL_FLOAT,					32,		EXT_TEXTURE_STORAGE, EXT_TEXTURE_FLOAT	},
			{ EPixelFormat::ALPHA16F,	GL_ALPHA16F,	GL_ALPHA,	GL_HALF,					16,		EXT_TEXTURE_STORAGE, EXT_TEXTURE_HALF	},
			// depth
			{ EPixelFormat::D16,		GL_DEPTH16,		GL_DEPTH,	GL_UNSIGNED_SHORT,			16,		EXT_TRUE,			EXT_TRUE	},
			{ EPixelFormat::D24,		GL_DEPTH24,		GL_DEPTH,	0,							24,		EXT_DEPTH24,		EXT_FALSE	},
			{ EPixelFormat::D32,		GL_DEPTH32,		GL_DEPTH,	GL_UNSIGNED_INT,			32,		EXT_DEPTH32,		EXT_DEPTH32	},
			// stencil
			{ EPixelFormat::S1,			GL_STENCIL1,	GL_STENCIL,	0,							1,		EXT_STENCIL1,		EXT_FALSE	},
			{ EPixelFormat::S4,			GL_STENCIL4,	GL_STENCIL,	0,							4,		EXT_STENCIL4,		EXT_FALSE	},
			{ EPixelFormat::S8,			GL_STENCIL8,	GL_STENCIL,	0,							8,		EXT_TRUE,			EXT_TRUE	},
			// depth stencil
			{ EPixelFormat::D24_S8,		GL_D24_S8,		GL_D_S,		GL_UINT24_8,				32,		EXT_DEPTH_STENCIL,	EXT_DEPTH_STENCIL	},
			// compressed
			{ EPixelFormat::RGB_ETC1,	GL_RGB_ETC1,	0,			0,							4,		EXT_FALSE,			EXT_COMPRESSED_ETC1 }
		};
		
#		undef EXT_TRUE
#		undef EXT_FALSE
#		undef EXT_RGB8_RGBA8
#		undef EXT_TEXTURE_RG
#		undef EXT_TEXTURE_STORAGE
#		undef EXT_TEXTURE_HALF
#		undef EXT_TEXTURE_FLOAT
#		undef EXT_DEPTH24
#		undef EXT_DEPTH32
#		undef EXT_DEPTH_STENCIL
#		undef EXT_STENCIL1
#		undef EXT_STENCIL4
#		undef EXT_COMPRESSED_ETC1


		ifmt = 0;
		fmt  = 0;
		type = 0;

		for (usize i = 0; i < CountOf(formats); ++i)
		{
			if ( format == formats[i].format )
			{
				if ( formats[i].framebufferExt()  ) {
					ifmt = formats[i].internalFormat;
				}

				if ( /*formats[i].textureExt()*/ true ) {
					fmt  = formats[i].pixelFormat;
					type = formats[i].pixelType;
				}

				bpp = formats[i].bitPerPixel;
				return true;
			}
		}
		return false;
	}

	
	// GetImageSize
	bool EPixelFormat::GetImageSize (OUT usize &imgSize, const uvec2 &dim, const EPixelFormat::type format)
	{
		uint	bpp = 0;
		bool	res = GetBitPerPixel( bpp, format );

		imgSize = ( dim.x * dim.y * bpp ) >> 3;
		return res;
	}


}	// Graphics
}	// Engine